/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stud.cp.user.dbaccess;

import java.math.BigInteger;
import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import stud.cp.core.dbaccess.DAO;
import stud.cp.core.dbaccess.DAOException;
import stud.cp.user.valueobjects.PropertyListValue;
import stud.cp.user.valueobjects.Parameter;

/**
 * Класс, описывающий доступ к таблице property_list_values
 *
 * @author Morfant
 */
public class ListValuesDAO implements DAO<PropertyListValue> {

    /**
     * Логгер.
     */
    private static Logger logger = Logger.getLogger("CPTNP");
    /**
     * Список названий колонок таблицы property_list_values.
     */
    private static String[] propertyListValuesColumnName = {"property_list_value_id", "property_type_def_id", "value"};
    /**
     * Коннект к базе данных.
     */
    private Connection connection = null;

    /**
     * Конструктор, который устанавливает коннект к базе данных.
     *
     * @param connection Связь с базой данных.
     */
    public ListValuesDAO(Connection connection) {
        this.connection = connection;
    }

    /**
     * Запрос, позволяющий получить запись по id.
     *
     * @param id ID
     * @return Запрос.
     */
    private String getQueryForGetById(BigInteger id) {
        StringBuilder query = new StringBuilder();
        query.append("SELECT property_list_value_id,property_type_def_id,value \n");
        query.append("FROM property_list_values \n");
        query.append("WHERE property_list_value_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Получение данных по ID
     *
     * @param id ID
     * @return Запись.
     * @throws DAOException Ошибка получения данных по ID
     */
    @Override
    public PropertyListValue getById(BigInteger id) throws DAOException {
        PropertyListValue propertListValue = null;
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForGetById(id));
            set = prestat.executeQuery();
            if (set.next()) {
                propertListValue =
                        new PropertyListValue(set.getBigDecimal(propertyListValuesColumnName[0]).toBigInteger(),
                        set.getBigDecimal(propertyListValuesColumnName[1]).toBigInteger(),
                        set.getString(propertyListValuesColumnName[2]));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка получения данных по ID", ex);
        } finally {
            logger.debug("SQL: \n " + getQueryForGetById(id));
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия PrepareStatement`а.", ex);
                }
            }
        }
        return propertListValue;
    }

    /**
     * Запрос на обновление записи в таблице.
     *
     * @param property_list_value_id ID
     * @param property_type_def_id Имя
     * @return Запрос.
     */
    private String getQueryForUpdate(BigInteger property_list_value_id, BigInteger property_type_def_id, String value) {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE property_list_values \n");
        query.append("SET property_type_def_id=");
        query.append(property_type_def_id);
        query.append(", \n");
        query.append("value='");
        query.append(value);
        query.append("' \n");
        query.append("WHERE property_list_value_id=");
        query.append(property_list_value_id);
        return query.toString();
    }

    /**
     * Метод, отвечающий за обновление данных.
     *
     * @param entry Запись.
     * @throws DAOException Ошибка при обновление данных.
     */
    @Override
    public void update(PropertyListValue entry) throws DAOException {
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(
                    getQueryForUpdate(
                    entry.getProperty_list_value_id(),
                    entry.getProperty_type_def_id(),
                    entry.getValue()));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка обновлени данных.", ex);
        } finally {
            logger.debug("SQL: \n " + getQueryForUpdate(
                    entry.getProperty_list_value_id(),
                    entry.getProperty_type_def_id(),
                    entry.getValue()));
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия PrepareStatement`а.", ex);
                }
            }
        }
    }

    /**
     * Запрос на добавление новой записи в таблицу.
     *
     * @param property_list_value_id ID
     * @param property_type_def_id Имя
     * @return Запрос.
     */
    private String getQueryForInsert(BigInteger property_list_value_id, BigInteger property_type_def_id, String value) {
        StringBuilder query = new StringBuilder();
        query.append("INSERT INTO property_list_values(property_list_value_id,property_type_def_id,value) \n");
        query.append("VALUES(");
        query.append(property_list_value_id);
        query.append(",");
        query.append(property_type_def_id);
        query.append(",'");
        query.append(value);
        query.append("')");
        return query.toString();
    }

    /**
     * Зарпос на получения следующего ID.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectNextID() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT property_list_values_seq.NEXTVAL from dual \n");
        return query.toString();
    }

    /**
     * Зарпос на получения максимального id из таблицы.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectMaxId() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT MAX(property_list_value_id) \n");
        query.append("FROM property_list_values");
        return query.toString();
    }

    /**
     * Метод, который создает новую запись в таблице.
     *
     * @param entry Запись.
     * @throws DAOException Ошибка создания новой записи.
     */
    @Override
    public BigInteger create(PropertyListValue entry) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        BigInteger index = null;
        CallableStatement proc;
        try {
            proc = connection.prepareCall("{ call GetNextIdentity(?,?)}");
            proc.setString(1, "list_values");
            proc.registerOutParameter(2, java.sql.Types.BIGINT);

            proc.execute();

            index = proc.getBigDecimal(2).toBigInteger();

            proc.close();
            prestat =
                    connection.prepareStatement(
                    getQueryForInsert(index, entry.getProperty_type_def_id(), entry.getValue()));
            prestat.executeUpdate();
            return index;
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка при создание записи.", ex);
        } finally {
            logger.debug("SQL: \n " + getQueryForSelectMaxId());
            logger.debug("SQL: \n " + getQueryForInsert(index, entry.getProperty_type_def_id(), entry.getValue()));
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия PrepareStatement`а.", ex);
                }
            }
        }
    }

    /**
     * Запрос, позволяющий при выполнении получить полностью данные из таблицы
     * weapon_types.
     *
     * @return Строка запроса.
     */
    private String getQueryForAllPropertyGroup() {
        StringBuilder query = new StringBuilder();
        query.append("select property_list_value_id,property_type_def_id,value \n");
        query.append("from property_list_values");
        return query.toString();
    }

    /**
     * Метод, выдающий список всех записей.
     *
     * @return Список записей.
     * @throws DAOException Ошибка получения данных.
     */
    @Override
    public List<PropertyListValue> getAll() throws DAOException {
        List<PropertyListValue> data_list = new LinkedList<PropertyListValue>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForAllPropertyGroup());
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new PropertyListValue(set.getBigDecimal(propertyListValuesColumnName[0]).toBigInteger(),
                        set.getBigDecimal(propertyListValuesColumnName[1]).toBigInteger(),
                        set.getString(propertyListValuesColumnName[2])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка получения списка данных.", ex);
        } finally {
            logger.debug("SQL: \n " + getQueryForAllPropertyGroup());
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия PrepareStatement`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Запрос, позволяющий при выполнении получить полностью данные из таблицы
     * weapon_types.
     *
     * @return Строка запроса.
     */
    private String getQueryForAllForListValueDef(BigInteger id) {
        StringBuilder query = new StringBuilder();
        query.append("select property_list_value_id,property_type_def_id,value \n");
        query.append("from property_list_values \n");
        query.append("where property_type_def_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Метод, выдающий список всех готовых значений для определенного
     * дефинишиона.
     *
     * @return Список записей.
     * @throws DAOException Ошибка получения данных.
     */
    public List<PropertyListValue> getAllForListValueDef(BigInteger id) throws DAOException {
        List<PropertyListValue> data_list = new LinkedList<PropertyListValue>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForAllForListValueDef(id));
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new PropertyListValue(set.getBigDecimal(propertyListValuesColumnName[0]).toBigInteger(),
                        set.getBigDecimal(propertyListValuesColumnName[1]).toBigInteger(),
                        set.getString(propertyListValuesColumnName[2])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка получения списка данных.", ex);
        } finally {
            logger.debug("SQL: \n " + getQueryForAllPropertyGroup());
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия PrepareStatement`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Зарпос на удаление из таблицы записи по id.
     *
     * @param id ID
     * @return Зарпос.
     */
    private String getQueryForDelete(BigInteger id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM property_list_values \n");
        query.append("WHERE property_list_value_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Запрос на все значения свойств, которые имееют в значении данное
     * списочное значение.
     *
     * @param property_list_value_id
     * @return
     */
    private String getQueryForAllPropertiesValuesForCurrentListValue(BigInteger property_list_value_id) {
        StringBuilder query = new StringBuilder();
        query.append("select property_value_id  \n");
        query.append("from property_values \n");
        query.append("where property_list_value_id=");
        query.append(property_list_value_id);
        return query.toString();
    }

    /**
     * Метод, позволяющий удалять данные по записи.
     *
     * @param id Запись.
     * @throws DAOException
     */
    @Override
    public void delete(BigInteger id) throws DAOException {
        PreparedStatement prestat = null;
        ResultSet set = null;
        try {
            List<BigInteger> data_list = new LinkedList<BigInteger>();
            prestat = connection.prepareStatement(getQueryForAllPropertiesValuesForCurrentListValue(id));
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(set.getBigDecimal(1).toBigInteger());
            }
            prestat.close();
            ParametersDAO propertyTypesDAO = new ParametersDAO(connection);
            Parameter propertyValue = null;
            for (BigInteger item : data_list) {
                propertyValue = propertyTypesDAO.getById(item);
                propertyValue.setProperty_list_value_id(null);
                propertyTypesDAO.update(propertyValue);
            }
            prestat = connection.prepareStatement(getQueryForDelete(id));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propeties", ex);
            throw new DAOException("Ошибка удаления данных.", ex);
        } finally {
            logger.debug("SQL: \n " + getQueryForDelete(id));
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия PrepareStatement`а.", ex);
                }
            }
        }
    }
}
